package com.gjzhao.fmmall.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.MapUtils;
import com.gjzhao.fmmall.excelStrategy.CustomMergeStrategy;
import com.gjzhao.fmmall.utils.EasyExcelUtil;
import com.gjzhao.fmmall.vo.easyExcel.Member;
import com.gjzhao.fmmall.utils.LocalJsonUtil;
import com.gjzhao.fmmall.vo.easyExcel.Order;
import com.gjzhao.fmmall.vo.easyExcel.OrderData;
import com.gjzhao.fmmall.vo.ResponseResultVO;
import com.gjzhao.fmmall.vo.easyExcel.Product;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

/**
 * 使用注意点： - 1。使用swagger 会导致各种问题，直接用浏览器或者用postman - 2。导入excel时，需要使用到 @RequestPart 修饰上传文件的参数
 *
 * @Description: EasyExcel 框架
 * @Author: gjzhao
 * @Date Created in 2022-01-09 10:45 上午
 */
@Controller
@Api(value = "EasyExcel导入与导出", tags = "EasyExcel 框架基本使用")
@RequestMapping("/easyExcel")
public class EasyExcelController extends BaseController {


    //@SneakyThrows(IOException.class)
    @SneakyThrows()
    @ApiOperation(value = "导出Excel会员列表（只有一级表头）")
    @RequestMapping(value = "/exportMemberList", method = RequestMethod.GET)
    public void exportMemberList(HttpServletResponse response) {

        logger.info("-----------开始导出---------");

        try {
            //导出excel文件名字
            String fileName = "会员列表" + "_" + DateUtil.format(new Date(), "yyyy-MM-dd");

            //TODO 获取本地测试数据
            List<Member> memberList = LocalJsonUtil.getListFromJson("json/members.json", Member.class);

            /*
            //设置响应头信息
            setExcelRespProp(response, fileName);

            EasyExcel.write(response.getOutputStream())
                     .head(Member.class)
                     .excelType(ExcelTypeEnum.XLSX)
                     .sheet("会员列表") //sheet标签名字
                     .doWrite(memberList);
             */

            //使用自定义工具类
            EasyExcelUtil.exportExcel(response, Member.class, ExcelTypeEnum.XLSX, fileName, "会员列表", memberList);

            logger.info("-----------正确导出，结束。---------");
        } catch (Exception e) {

            /*
            //如果导出失败，重置response，封装失败结果及失败原因
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");

            Map<String, String> map = MapUtils.newHashMap();
            map.put("status", "failure");
            map.put("message", "下载文件失败，错误原因：" + e.getMessage());

            response.getWriter().println(JSONUtil.toJsonStr(map));
             */

            logger.info("-----------错误导出:[" + e.getMessage() + "]，结束！---------");
        }
    }


    @SneakyThrows
    @ApiOperation("导入Excel会员列表（一级表头）")
    @RequestMapping(value = "/importMemberList", method = RequestMethod.POST)
    @ResponseBody
    public ResponseResultVO importMemberList(@RequestPart("file") MultipartFile file) {

        logger.info("-----------开始导入---------");

        ResponseResultVO resultVO = new ResponseResultVO();
        try {

            List<Member> memberList = EasyExcel.read(file.getInputStream())
                                               .head(Member.class)
                                               .sheet()
                                               .doReadSync();


            resultVO.setMessage("success");
            resultVO.setData(memberList);
            logger.info("-----------正确导入:[" + memberList + "],结束。---------");
        } catch (Exception e) {
            //如果导入失败，封装失败结果及失败原因
            resultVO.setMessage("下载文件失败，错误原因：" + e.getMessage());
            logger.info("-----------错误导入:[" + e.getMessage() + "]，结束！---------");
        }

        return resultVO;
    }


    @SneakyThrows
    @ApiOperation(value = "导出订单列表Excel（嵌套二级表头导出）")
    @RequestMapping(value = "/exportOrderList", method = RequestMethod.GET)
    public void exportOrderList(HttpServletResponse response) {

        logger.info("-----------开始导出---------");

        try {
            //导出excel文件名字
            String fileName = "订单列表" + "_" + DateUtil.format(new Date(), "yyyy-MM-dd");
            //设置响应信息
            setExcelRespProp(response, fileName);

            //TODO 获取本地测试数据
            List<Order> orderList = getOrderList();
            //封装导出的excel字段信息
            List<OrderData> orderDataList = convert(orderList);

            //导出
            EasyExcel.write(response.getOutputStream())
                     .head(OrderData.class)
                     .registerWriteHandler(new CustomMergeStrategy(OrderData.class)) //注册自定义策略
                     .excelType(ExcelTypeEnum.XLSX)
                     .sheet("订单列表")
                     .doWrite(orderDataList);
            logger.info("-----------正确导出，结束。---------");
        } catch (Exception e) {
            //如果导出失败，重置response，封装失败结果及失败原因
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");

            Map<String, String> map = MapUtils.newHashMap();
            map.put("status", "failure");
            map.put("message", "下载文件失败，错误原因：" + e.getMessage());
            response.getWriter().println(JSONUtil.toJsonStr(map));

            logger.info("-----------错误导出:[" + e.getMessage() + "]，结束！---------");
        }

    }

    @SneakyThrows
    @ApiOperation("导入Excel订单列表（嵌套二级表头导入）")
    @RequestMapping(value = "/importOrderList", method = RequestMethod.POST)
    @ResponseBody
    public ResponseResultVO importOrderList(@RequestPart("file") MultipartFile file) {

        logger.info("-----------开始导入---------");

        ResponseResultVO resultVO = new ResponseResultVO();
        try {
            List<OrderData> orderDataList = EasyExcel.read(file.getInputStream())
                                                     .head(OrderData.class)
                                                     .sheet()
                                                     .doReadSync();

            resultVO.setMessage("success");
            resultVO.setData(orderDataList);
            logger.info("-----------正确导入:[" + orderDataList + "],结束。---------");
        } catch (Exception e) {
            //如果导入失败，封装失败结果及失败原因
            resultVO.setMessage("下载文件失败，错误原因：" + e.getMessage());
            logger.info("-----------错误导入:[" + e.getMessage() + "]，结束！---------");
        }

        return resultVO;
    }


    /**
     * 设置excel下载响应头属性
     *
     * @param response    响应
     * @param rawFileName 导出excel名字
     * @throws UnsupportedEncodingException
     */
    private void setExcelRespProp(HttpServletResponse response, String rawFileName) throws UnsupportedEncodingException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        //URLEncoder.encode 用以防止中文乱码
        String fileName = URLEncoder.encode(rawFileName, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
    }


    /**
     * TODO 查询的订单信息
     *
     * @return
     */
    private List<Order> getOrderList() {
        List<Order> orderList = LocalJsonUtil.getListFromJson("json/orders.json", Order.class);
        List<Product> productList = LocalJsonUtil.getListFromJson("json/products.json", Product.class);
        List<Member> memberList = LocalJsonUtil.getListFromJson("json/members.json", Member.class);
        for (int i = 0; i < orderList.size(); i++) {
            Order order = orderList.get(i);
            order.setMember(memberList.get(i));
            order.setProductList(productList);
        }
        return orderList;
    }

    /**
     * TODO 将嵌套的 Order 对象列表转换为 OrderData 对象列表
     *
     * @param orderList
     * @return
     */
    private List<OrderData> convert(List<Order> orderList) {
        List<OrderData> result = new ArrayList<>();
        for (Order order : orderList) {
            //获取嵌套的商品列表信息
            List<Product> productList = order.getProductList();
            for (Product product : productList) {
                OrderData orderData = new OrderData();
                BeanUtil.copyProperties(product, orderData);
                BeanUtil.copyProperties(order, orderData);
                result.add(orderData);
            }
        }
        return result;
    }
}
